#ifndef CDGLIB_H
#define CDGLIB_H

#include <fstream>
#include <string>

#define SC_MASK           0x3F
#define SC_CDG_COMMAND    0x09

// Instructions
#define CDG_MEMORYPRESET  1
#define CDG_BORDERPRESET  2
#define CDG_TILEBLOCK     6
#define CDG_SCROLLPRESET  20
#define CDG_SCROLLCOPY    24
#define CDG_DEFINETRANS   28
#define CDG_LOADCOLOR0_7  30
#define CDG_LOADCOLOR8_15 31
#define CDG_TILEBLOCK_XOR 38

// CDG-file consists of 24-bytes pkgs
typedef struct {
    char command;
    char instruction;
    char parityQ[2];
    char data[16];
    char parityP[4];
} SubCode_t;

// Data contains:

// Memory preset (subCode.instruction==1)
typedef struct {
    char color;// Only lower 4 bits are used, mask with 0x0F
    char repeat;// Only lower 4 bits are used, mask with 0x0F
    char filler[14];
} CDG_MemPreset_t;


// Border Preset (subCode.instruction==2)
typedef struct {
    char color;// Only lower 4 bits are used, mask with 0x0F
    char filler[15];
} CDG_BorderPreset_t;


// Tile Block Normal (subCode.instruction==6)
// Tile Block XOR (subCode.instruction==38)
typedef struct {
    char color0;// Only lower 4 bits are used, mask with 0x0F
    char color1;// Only lower 4 bits are used, mask with 0x0F
    char row;// Only lower 5 bits are used, mask with 0x1F
    char column;// Only lower 6 bits are used, mask with 0x3F
    char tilePixels[12];// Only lower 6 bits of each byte are used
} CDG_Tile_t;


// Scroll Preset (subCode.instruction==20)
// Scroll Copy (subCode.instruction==24)
typedef struct {
    char color;// Only lower 4 bits are used, mask with 0x0F
    char hScroll;// Only lower 6 bits are used, mask with 0x3F
    char vScroll;// Only lower 6 bits are used, mask with 0x3F
} CDG_Scroll_t;

// Define trans (subCode.instruction==28)
typedef struct {
    char color;// Only lower 4 bits are used, mask with 0x0F
    char filler[15];
} CDG_Transparent_t;

// Load Color Table Lo   [colors 0 thru 7]  (subCode.instruction==30)
// Load Color Table High [colors 8 thru 15] (subCode.instruction==31)
typedef struct {
    short colorSpec[8];  // AND with 0x3F3F to clear P and Q channel
} CDG_LoadCLUT_t;



typedef struct {
    int tl_x; //Topleft x
    int tl_y; //Topleft y
    int br_x; //Bottomright x
    int br_y; //Bottomright y
} CDG_Area_t;

#define cdgImageWidth  300
#define cdgImageHeight 216

class CDGlib
{
  public:
    CDGlib();
    ~CDGlib();
    bool start(const std::string& filename, bool useTransp=true, bool useTransBkg=true, bool useTransBorder=true);
    void stop();

    void handlePackets(int amount);
    void getUpdateArea(CDG_Area_t& getarea);

    unsigned int getLength() {return (buffSize / sizeof(SubCode_t))*1000/300; };
    unsigned int getCurrent() {return parseptr*1000/300;};

    void generateImage();
    void generateFrame();

    void switchTransparency(void);
    void switchTransparentBkg(void);

 private:
    void clear();

    void MemoryPreset(const CDG_MemPreset_t& data);
    void BorderPreset(const CDG_BorderPreset_t& data);
    void TitleBlock(bool XOR,const CDG_Tile_t& data);
    void ScrollPreset(const CDG_Scroll_t& data);
    void ScrollCopy(const CDG_Scroll_t& data);
    void Scroll(const CDG_Scroll_t& data, bool copy);
    void DefineTrans(const CDG_Transparent_t& data);
    void LoadColor(int offset, const CDG_LoadCLUT_t& data);

    void setUpdateArea(int topLeftX, int topLeftY, int bottomRightX, int bottomRightY);
    void resetUpdateArea();

    void fillArea(int color, int topLeftX, int topLeftY, int bottomRightX, int bottomRightY);

 public:
    unsigned char image[cdgImageHeight][cdgImageWidth][4];
    unsigned char frame[cdgImageHeight][cdgImageWidth][4];

 private:
    CDG_Area_t area;

    // CDG-file info
    char *       buffer;
    size_t       buffSize;
    unsigned int parseptr;

    // Colors
    unsigned char colormap[cdgImageHeight][cdgImageWidth];
    unsigned char colors[16][4];

    // Transparency
    int color_trans;
    int color_border;
    int color_bg;
    bool trans_trans;
    bool trans_border;
    bool trans_bg;
};

#endif
